##   game.py
##   $Id$
##   $Rev: $
##   Copyright (C) 2007 Sean Lin
##
##   This program is free software; you can redistribute it and/or modify
##   it under the terms of the GNU General Public License as published by
##   the Free Software Foundation; either version 2, or (at your option)
##   any later version.
##
##   This program is distributed in the hope that it will be useful,
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##   GNU General Public License for more details.
import types
import version
import common.xmpp as xmpp
#from common.gbase import if_gbase
import card
import plugin
import status

from common.xmpp import debug
Debug=debug
Debug.DEBUGGING_IS_ON=1
Debug.Debug.colors['OUAT']=debug.color_purple

class ADMIN_COMMAND(Exception):pass
class MSG_COMMAND(Exception):pass
class NOMAN_COMMAND(Exception):pass
class NO_COMMAND(Exception):pass
class DISCARD_COMMAND(Exception):pass
class EXIT_COMMAND(Exception):pass

class Hall:
    ""
    def __init__(self,profile,conf,conn, reactor, users=[], debug = ['always','nodebuilder']):
        self.profile = profile
        self.conn = conn
        self.reactor = reactor
        self.user_list = users
        self.cmdchrs='/='
        
        self.sign_map = {}
       
        if debug and type(debug)<>list: 
            debug=['always', 'nodebuilder']
        
        self._DEBUG=Debug.Debug(debug)
        self.DEBUG=self._DEBUG.Show
        self.debug_flags=self._DEBUG.debug_flags
        self.DBG = 'OUAT'
        self.debug_flags.append(self.DBG)
        self._owner=self
        if conf:
            self.conf = conf
        else:
            self.conf =\
            {'sysprompt': '>>>',
            }
        
        plugin.command_plugin.Cmd_Me().PlugIn(self)
        plugin.command_plugin.Cmd_Sign().PlugIn(self)
        #plugin.fight_plugin.Cmd_Fight().PlugIn(self)
        self.room_list=[]
        self.init_command()

    def init_command(self):
        self.__commands={}
        for i in dir(self):
            if i[-7:]=='Handler' and i[:-7].lower()==i[:-7]:
                self.__commands[i[:-7]]=getattr(self,i)

    def add_user(self,user, sign=''):
        user = self.getdisplayname(user).lower()
        if user not in self.user_list:
            for i in self.room_list:
                if i.user_is_in(user):
                    i.add_user(user)
                    return
            self.user_list.append(user)
            self.systoall('<%s> joins this room. \r\n %s'%(self.getdisplayname(user), status.get_status()))
            self.namesHandler(user, '')
        if '' != sign:
            if not self.sign_map.has_key(user):
                self.sign_map[user] = sign
        pass

    def remove_user(self,user):
        user = self.getdisplayname(user).lower()
        for i in self.room_list:
            if i.user_is_in(user):
                i.remove_user(user)
                return
        try:
            self.user_list.remove(user)
            self.systoall('<%s> has left'%(self.getdisplayname(user)))
        except:
            pass

    def user_is_in(self, user):
        user = self.getdisplayname(user).lower()
        for i in self.room_list:
            if i.user_is_in(user):
                return True
        return user in self.user_list
    
    def get_users(self):
        return self.user_list

    def process_message(self, msg):
        whoid = self.getjid(msg.getFrom())
        if msg.getError()!=None:
            return;
        elif msg.getBody():
            #check quality
            if msg.getFrom().getStripped() == self.getjid(self.profile.getNode()):
                return
            for i in self.room_list:
                if i.user_is_in(unicode(msg.getFrom())):
                    try:
                        i.process_message(msg)
                        return
                    except DISCARD_COMMAND:
                        subroom_user = i.get_users()
                        self.room_list.remove(i)
                        for user in subroom_user:
                            self.add_user(user)
                        return
                        pass
                    except EXIT_COMMAND:
                        self.add_user(unicode(msg.getFrom()))
                        return
                        pass
            self.add_user(unicode(msg.getFrom()))
            if len(msg.getBody())>1024:
                self.systoall("%s is being a moron trying to flood the channel"%self.getdisplayname(msg.getFrom()))
            elif msg.getBody()[:1] in self.cmdchrs:
                try:
                    self.cmd(msg.getFrom(),msg.getBody())
                except NO_COMMAND:
                    self.sendtoall('<%s> %s' % (self.getdisplayname(msg.getFrom(), is_sign=True), msg.getBody()),
                        butnot=[self.getdisplayname(msg.getFrom()).lower()],
                        )
            else:
                self.sendtoall('<%s> %s' % (self.getdisplayname(msg.getFrom(), is_sign=True), msg.getBody()),
                    butnot=[self.getdisplayname(msg.getFrom()).lower()],
                    )
    
    def cmd(self, who, msg):
        if " " in msg:
            cmd,msg=msg.split(" ",1)
        else:
            cmd,msg=msg.strip(),""
        if cmd[:1] in self.cmdchrs:
            cmd=cmd[1:]
        cmd = cmd.lower()
        func = None
        try:
            if self.__commands.has_key(cmd):
                func = self.__commands[cmd]
                func(who, msg)
            else:
                raise NO_COMMAND
                return;
                self.systoone(who, 'Unknown command "%s"'%cmd)
        except ADMIN_COMMAND:
            self.systoone(who, _('This is admin command, you have no permision to use.'))
        except MSG_COMMAND:
            self.systoone(who, str(func.__doc__))
        except NOMAN_COMMAND:
            self.systoone(who, _('There is no this person'))
            pass

    def helpHandler(self, who, msg):
        '"/help" Show this help message'
        jid = who.getStripped()
        self.systoone(who, 'Commands: \r\n%s'%(' /' + ' /'.join(["%-20s%s\r\n" % (x, unicode(y.__doc__) or "") for x, y in self.__commands.items()])))
        self.systoone(who, 'See http://code.google.com/p/ouat for more details.')
        
    def namesHandler(self, who, msg):
        '"/names" List all the people in the room'
        names = ''
        for user in self.user_list:
            user = user + ' (' + self.sign_map.get(user, '') + ')\r\n'
            names += user
        self.systoone(who, 'Names: total (%d)\r\n%s'%(len(self.user_list), "".join(names)))

    def msgHandler(self, who, msg):
        '"/msg nick message" Send a private message to someone'
        if not ' ' in msg:
            self.systoone(who, 'Usage: /msg nick message')
        else:
            target,msg = msg.split(' ',1)
            self.sendtoone(self.getjid(target), '*<%s>* %s'%(self.getdisplayname(who), msg))
            self.systoone(who,' to: %s > %s'%(self.getdisplayname(target), msg))

    def versionHandler(self,who, msg):
        '"/version" Show version of this bot'
        self.systoone(who, 'Version: %s \r\nDev Version: %s \r\nSee http://code.google.com/p/ouat for more details' % (version.VERSION, version.REVISION))

    def getdisplayname(self, x, is_sign = False):
        '''
        Changes a user@domain/resource to a displayable nick (user)
        is_sign: True:return a signed nickname rather than gtalk account, if any.
        '''
        server = self.profile.getDomain()
        x=unicode(x)
        if '/' in x:
            x = x[:x.find("/")]
        if '@' in x and x[x.find('@'):] == "@" + server:
            x = x[:x.find("@")]
        if is_sign:
            x = self.sign_map.get(x.lower(), x)
        return x

    def getindexname(self,x):
        return self.getdisplayname(x).lower()
    
    def getjid(self, x):
        "returns a full jid from a display name"
        server = self.profile.getDomain()
        x = self.getdisplayname(x)
        if '@' not in x:
            x = x + "@" + server
        return x

    def sendtoone(self, who, msg):
        m = xmpp.Message(self.getjid(who), msg)
        jid=self.conn.User+'@'+self.conn.Server+'/'+self.conn.Resource
        m.setFrom(jid)
        m.setType('chat')
        self.conn.send(m)

    def sendtoall(self, msg,butnot=[],including=[]):
        r = self.conn.getRoster()
        user_sent_list = []
        for i in r.getItems():
            user = self.getdisplayname(i).lower()
            if user in butnot:
                continue
            if user in self.user_list:
                if user in user_sent_list:
                    continue
                else:
                    user_sent_list.append(user)
                #if r.getShow(i) in ['available','chat','online',None]:
                self.sendtoone(i, msg)
            
    def sendtoadmin(self, msg,butnot=[],including=[]):
        r = self.conn.getRoster()
        for i in self.user_list:
            if not isadmin(i): 
                continue
            if self.getdisplayname(i).lower() in butnot:
                continue
            state=r.getShow(unicode(i))
            if state in ['available','chat','online',None] or self.getdisplayname(i) in including :
                self.sendtoone(i,msg)

    def systoall(self, msg, butnot=[], including=[]):
        user = butnot[:]
        self.sendtoall(self.conf['sysprompt'] + ' ' + msg, user, including)
        
    def systoone(self, who, msg):
        self.sendtoone(who, self.conf['sysprompt'] + ' ' + msg)
        
    def systoadmin(self, msg, butnot=[], including=[]):
        self.sendtoadmin(self.conf['sysprompt'] + ' ' + msg, butnot, including)

            
